# tk事件的字母键，只能用小写字母
# B1-Motion的语义并不是“按住B1移动时位于其上”，而是“由其上开始的，按住B1的移动”。和B1-Leave, B1-Enter相似

ANYSTATE1 = 233
ANYSTATE2 = 66

DEBUG = True

class Functioner:
    """根据eventer的state1和state2执行不同过程
        state2是全局的"""
    def __init__(self, eventer, eventstring, tag, f_state1_state2=None):
        self.eventer = eventer
        self.extra_name = eventstring if tag is None else eventstring + '~' + tag
        self.d = {}
        if f_state1_state2 is not None:
            f, state1, state2 = f_state1_state2
            self.d[(state1, state2)] = f
            if DEBUG: print(f"{self.extra_name}~{state1}~{state2}", "reg")


    def add(self, f_state1_state2):
        f, state1, state2 = f_state1_state2
        assert (state1, state2) not in self.d.keys(), "重复绑定"
        self.d[(state1, state2)] = f
        if DEBUG: print(f"{self.extra_name}~{state1}~{state2}", "reg")


    def call(self, e):
        if DEBUG: print("                        ", f"{self.extra_name}~{self.eventer.state1}~{self.eventer.state2}")
        f = self.d.get((self.eventer.state1, self.eventer.state2))
        if f is not None:
            return f(e)
        f = self.d.get((ANYSTATE1, self.eventer.state2))
        if f is not None:
            return f(e)
        f = self.d.get((self.eventer.state1, ANYSTATE2))
        if f is not None:
            return f(e)
        f = self.d.get((ANYSTATE2, ANYSTATE2))
        if f is not None:
            return f(e)
        # if DEBUG: print("can't reply")
        

        

class Eventer: 
    """鼠标事件，tag型鼠标事件，键盘事件
        键盘事件全部视为全局，由主窗体接收；state2为所有eventer共享"""
    state2 = None
    def __init__(self, b_canvas=None, b_tag=None, b_key=None, u_canvas=None, u_tag=None, u_key=None):  # bind是canvas_bind
        self.fcanvas_bind = b_canvas
        self.ftag_bind = b_tag
        self.fkey_bind = b_key
        self.fcanvas_unbind = u_canvas
        self.ftag_unbind = u_tag
        self.fkey_unbind = u_key

        self.d = {}
        self.state1 = "nothing"


    def bind(self, eventstring, state1, state2=None):               # 带参修饰器，参数从右往左读
        def _(f):
            r = self.d.get(eventstring)
            if r is None:
                functioner = Functioner(self, eventstring, None, (f, state1, state2))
                self.fcanvas_bind(eventstring, lambda e: functioner.call(e))
                self.d[eventstring] = functioner
            else:
                r.add((f, state1, state2))
        return _

    def tag_bind(self, eventstring, tag, state1, state2=None):
        def _(f):
            r = self.d.get((tag, eventstring))
            if r is None:
                functioner = Functioner(self, eventstring, tag, (f, state1, state2))
                self.ftag_bind(tag, eventstring, lambda e: functioner.call(e))
                self.d[(tag, eventstring)] = functioner
            else:
                r.add((f, state1, state2))
        return _

    def key_bind(self, eventstring, state1, state2=None):
        def _(f):
            r = self.d.get(eventstring)
            if r is None:
                functioner = Functioner(self, eventstring, None, (f, state1, state2))
                self.fkey_bind(eventstring, lambda e: functioner.call(e))
                self.d[eventstring] = functioner
            else:
                r.add((f, state1, state2))
        return _
    
    def second_key_bind(self, eventstring, state2):      # 负责state2，不受state1影响
        def _(f):
            r = self.d.get(eventstring)
            if r is None:
                functioner = Functioner(self, eventstring, None, (f, ANYSTATE1, state2))
                self.fkey_bind(eventstring, lambda e: functioner.call(e))
                self.d[eventstring] = functioner
            else:
                r.add((f, ANYSTATE1, state2))
        return _

    def change_state(self, state1):      # 建议写在return前一行
        if DEBUG: print("change state1:", state1)
        self.state1 = state1
        return self

    def keep_state(self):
        return self

    def change_state2(self, state2):
        if DEBUG: print("change state2:", state2)
        Eventer.state2 = state2
        return self

    def keep_state2(self):
        return self

    def close(self):
        pass
